"""
权限验证服务

提供权限验证相关的功能，包括：
- 权限检查和验证
- 角色检查和验证
- 权限装饰器
- 权限服务类
"""

from functools import wraps
from typing import List, Optional, Callable
from fastapi import HTTPException, status, Depends
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from db.models import User, Role, Permission, RolePermission, UserRole
from db.session import get_db


class PermissionService:
    """
    权限服务类
    
    提供权限检查和验证的核心功能
    """
    
    def __init__(self, db: AsyncSession):
        """
        初始化权限服务
        
        Args:
            db: 数据库会话
        """
        self.db = db
    
    async def get_user_permissions(self, user_id: int) -> List[str]:
        """
        获取用户所有权限代码
        
        Args:
            user_id: 用户ID
            
        Returns:
            List[str]: 权限代码列表
        """
        # 查询用户角色
        user_roles_result = await self.db.execute(
            select(RolePermission.permission_id)
            .join(Role, RolePermission.role_id == Role.id)
            .join(UserRole, UserRole.role_id == Role.id)
            .where(UserRole.user_id == user_id)
        )
        permission_ids = [row[0] for row in user_roles_result.all()]
        
        if not permission_ids:
            return []
        
        # 查询权限代码
        permissions_result = await self.db.execute(
            select(Permission.code).where(Permission.id.in_(permission_ids))
        )
        return [row[0] for row in permissions_result.all()]
    
    async def has_permission(self, user_id: int, permission_code: str) -> bool:
        """
        检查用户是否有指定权限
        
        Args:
            user_id: 用户ID
            permission_code: 权限代码
            
        Returns:
            bool: 是否有权限
        """
        user_permissions = await self.get_user_permissions(user_id)
        return permission_code in user_permissions
    
    async def has_any_permission(self, user_id: int, permission_codes: List[str]) -> bool:
        """
        检查用户是否有任意一个权限
        
        Args:
            user_id: 用户ID
            permission_codes: 权限代码列表
            
        Returns:
            bool: 是否有任意一个权限
        """
        user_permissions = await self.get_user_permissions(user_id)
        return any(perm in user_permissions for perm in permission_codes)
    
    async def has_all_permissions(self, user_id: int, permission_codes: List[str]) -> bool:
        """
        检查用户是否有所有权限
        
        Args:
            user_id: 用户ID
            permission_codes: 权限代码列表
            
        Returns:
            bool: 是否有所有权限
        """
        user_permissions = await self.get_user_permissions(user_id)
        return all(perm in user_permissions for perm in permission_codes)


async def get_permission_service(db: AsyncSession = Depends(get_db)) -> PermissionService:
    """
    获取权限服务实例
    
    Args:
        db: 数据库会话
        
    Returns:
        PermissionService: 权限服务实例
    """
    return PermissionService(db)


def require_permission(permission_code: str):
    """
    装饰器：要求指定权限
    
    Args:
        permission_code: 权限代码
        
    Returns:
        Callable: 装饰器函数
    """
    def decorator(func: Callable):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            # 从kwargs中获取db和current_user
            db = kwargs.get('db')
            current_user = kwargs.get('current_user')
            
            if not db or not current_user:
                raise HTTPException(
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    detail="权限验证失败：缺少必要参数"
                )
            
            permission_service = PermissionService(db)
            
            # 检查用户权限
            if not await permission_service.has_permission(current_user.id, permission_code):
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail=f"权限不足：需要 {permission_code} 权限"
                )
            
            return await func(*args, **kwargs)
        return wrapper
    return decorator


def require_any_permission(permission_codes: List[str]):
    """
    装饰器：要求任意一个权限
    
    Args:
        permission_codes: 权限代码列表
        
    Returns:
        Callable: 装饰器函数
    """
    def decorator(func: Callable):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            db = kwargs.get('db')
            current_user = kwargs.get('current_user')
            
            if not db or not current_user:
                raise HTTPException(
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    detail="权限验证失败：缺少必要参数"
                )
            
            permission_service = PermissionService(db)
            
            # 检查用户权限
            if not await permission_service.has_any_permission(current_user.id, permission_codes):
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail=f"权限不足：需要以下权限之一 {', '.join(permission_codes)}"
                )
            
            return await func(*args, **kwargs)
        return wrapper
    return decorator


def require_all_permissions(permission_codes: List[str]):
    """
    装饰器：要求所有权限
    
    Args:
        permission_codes: 权限代码列表
        
    Returns:
        Callable: 装饰器函数
    """
    def decorator(func: Callable):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            db = kwargs.get('db')
            current_user = kwargs.get('current_user')
            
            if not db or not current_user:
                raise HTTPException(
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    detail="权限验证失败：缺少必要参数"
                )
            
            permission_service = PermissionService(db)
            
            # 检查用户权限
            if not await permission_service.has_all_permissions(current_user.id, permission_codes):
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail=f"权限不足：需要所有权限 {', '.join(permission_codes)}"
                )
            
            return await func(*args, **kwargs)
        return wrapper
    return decorator


def require_role(role_code: str):
    """
    装饰器：要求指定角色
    
    Args:
        role_code: 角色代码
        
    Returns:
        Callable: 装饰器函数
    """
    def decorator(func: Callable):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            db = kwargs.get('db')
            current_user = kwargs.get('current_user')
            
            if not db or not current_user:
                raise HTTPException(
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    detail="权限验证失败：缺少必要参数"
                )
            
            # 检查用户角色
            user_role_result = await db.execute(
                select(Role)
                .join(UserRole, UserRole.role_id == Role.id)
                .where(UserRole.user_id == current_user.id, Role.code == role_code)
            )
            user_role = user_role_result.scalar_one_or_none()
            
            if not user_role:
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail=f"权限不足：需要 {role_code} 角色"
                )
            
            return await func(*args, **kwargs)
        return wrapper
    return decorator


def require_any_role(role_codes: List[str]):
    """
    装饰器：要求任意一个角色
    
    Args:
        role_codes: 角色代码列表
        
    Returns:
        Callable: 装饰器函数
    """
    def decorator(func: Callable):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            db = kwargs.get('db')
            current_user = kwargs.get('current_user')
            
            if not db or not current_user:
                raise HTTPException(
                    status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
                    detail="权限验证失败：缺少必要参数"
                )
            
            # 检查用户角色
            user_roles_result = await db.execute(
                select(Role.code)
                .join(UserRole, UserRole.role_id == Role.id)
                .where(UserRole.user_id == current_user.id)
                .where(Role.code.in_(role_codes))
            )
            user_roles = [row[0] for row in user_roles_result.all()]
            
            if not any(role in user_roles for role in role_codes):
                raise HTTPException(
                    status_code=status.HTTP_403_FORBIDDEN,
                    detail=f"权限不足：需要以下角色之一 {', '.join(role_codes)}"
                )
            
            return await func(*args, **kwargs)
        return wrapper
    return decorator


# 权限代码常量
class PermissionCodes:
    """
    权限代码常量类
    
    定义系统中所有权限的代码常量，包括：
    - 用户管理权限
    - 角色管理权限
    - 权限管理权限
    - 系统管理权限
    - 个人信息权限
    - 组件管理权限
    """
    # 用户管理权限
    USER_READ = "user:read"          # 读取用户信息
    USER_CREATE = "user:create"        # 创建用户
    USER_UPDATE = "user:update"        # 更新用户信息
    USER_DELETE = "user:delete"        # 删除用户
    
    # 角色管理权限
    ROLE_READ = "role:read"          # 读取角色信息
    ROLE_CREATE = "role:create"        # 创建角色
    ROLE_UPDATE = "role:update"        # 更新角色信息
    ROLE_DELETE = "role:delete"        # 删除角色
    
    # 权限管理权限
    PERMISSION_READ = "permission:read"      # 读取权限信息
    PERMISSION_CREATE = "permission:create"  # 创建权限
    PERMISSION_UPDATE = "permission:update"  # 更新权限信息
    PERMISSION_DELETE = "permission:delete"  # 删除权限
    
    # 系统管理权限
    SYSTEM_CONFIG = "system:config"    # 系统配置
    SYSTEM_LOG = "system:log"          # 系统日志
    
    # 个人信息权限
    PROFILE_READ = "profile:read"      # 读取个人信息
    PROFILE_UPDATE = "profile:update"  # 更新个人信息
    PROFILE_PASSWORD = "profile:password"  # 修改密码
    
    # 组件管理权限
    WIDGET_READ = "widget:read"        # 读取组件信息
    WIDGET_CREATE = "widget:create"      # 创建组件
    WIDGET_UPDATE = "widget:update"      # 更新组件信息
    WIDGET_DELETE = "widget:delete"      # 删除组件
